<?php
/*
*All rights reserved: Json.
*Links:http://www.liyaoquan.cn.
*Links:http://imarkchina.cn.
*Links:http://www.imarkchina.cn.
*/
abstract class Db {

	Protected $config = array(
		'DB_TYPE'          => 'mysql',
		'DB_DNS'           => '',
		'DB_HOST'          => 'localhost',
		'DB_PORT'          => 3306,
		'DB_NAME'          => '',
		'DB_USER'          => 'root',
		'DB_PASSWORD'      => '',
		'DB_CHARSET'       => 'UTF8',
		'DB_LONG_CONNECT'  => false,
		'DB_PREFIX'        => '',
		'DB_PREFIX_VAR'    => '',
		);

	Private function _initConfig() {
		if (!empty($this->config['DB_DSN']) && empty($this->config['DB_TYPE'])) {
			$array = explode(':', $this->config['DB_DSN']);
			$this->config['DB_TYPE'] = array_shift($array);
		}
	}

	Protected function __construct() {
		$this->config = array_merge($this->config, C());
	}

	Protected $table;

	Public function setTable($table) {
		$this->_initConfig();
		$this->table = trim($table) ? $this->config['DB_PREFIX'].$table : '';
	}

	Protected Static $countQuery = 0;

	Public Static function getCountQuery() {
		return self::$countQuery;
	}

	Public function getType() {
		return $this->config['DB_TYPE'];
	}

	Public function parse($type, $params) {
		switch ($type) {
			case 'prefix':
			return str_replace($this->config['DB_PREFIX_VAR'], $this->config['DB_PREFIX'], $params);
			case 'field':
			if (is_array($params)) {
				if (!$params) return '*';
				$fields = array();
				foreach ($params as $field) {
					$field = trim($field);
					if ($field != '*') $field = '`'.$field.'`';
					$fields[] = $field;
				}
				return join(',', $fields);
			} else {
				return trim($params) ? $params : '*';
			}
			case 'group':
				return trim($params) ? ' GROUP BY '.$params : '';
			case 'order':
				return trim($params) ? ' ORDER BY '.$params : '';
			case 'limit':
				return trim($params) ? ' LIMIT '.$params : '';
			case 'join':
				if (is_array($params)) {
					$join  = join(' LEFT JOIN ', $params);
					return ' LEFT JOIN '.$this->parse('prefix', $join);
				}
				break;
			case 'where':
			if (!$params) return;
			if (!is_array($params)) return ' WHERE '.$params;
			$space = ' AND ';
			if (isset($params['_space'])) {
				$params['_space'] = strtoupper($params['_space']);
				if ($params['_space'] == 'OR') $space = ' '.$params['_space'].' ';
				unset($params['_space']);
			}
			$result = ' WHERE ';
			if (is_array($params)) {
				foreach ($params as $key => $value) {
					if (is_array($value)) { //eg: array('id' => array(1,2,3))
						$in = join('\',\'', array_map(array($this, 'escapeString'), $value));
						$in = trim($in, ',');
						$result .= $key.' IN(\''.$in.'\')';
						//条件key中带 > < LIKE 等逻辑符号
						//eg: array('add_time >'=>'2010-10-1')
						//eg: array('username LIKE' => '%[_%]%'); LIKE 条件用[]包括将自动转义通用匹配符号%_
					} else if (strpos($key, ' ')) {
						$ESCAPE = false;
						if (strpos(strtolower($key), 'like')) {
							preg_match_all('/\[(.*)\]/iD', $value, $match);
							if (!empty($match[1][0])) {
								$replace = str_replace('%', '/%', str_replace('_', '/_', $match[1][0]));
								$value = preg_replace("/\[(.*)\]/iD", $replace, $value);
								if (strpos($value, '/')) $ESCAPE = true;
							}
						}
						$result .= $key.' \''.$this->escapeString($value).'\'';
						if ($ESCAPE)
						$result .= " ESCAPE '/'";
					} else {
						$result .= $key.' = \''.$this->escapeString($value).'\'';
					}
					$result .= ' '.$space.' ';
				}
				$result = rtrim($result, $space.' ');
			} else {
				return $result.$params;
			}
			return $result;
		}
	}

	Private $_args = array(
		'field'    => '',
		'where' => '',
		'group' => '',
		'order'  => '',
		'limit'    => '',
		'alias'    => '',
		'join'     => ''
	);

	Public function __call($method, $args) {
		$method = strtolower($method);
		if (array_key_exists($method, $this->_args)) {
			if ($method == 'join') {
				$this->_args['join'][] = $args[0];
			} else {
				$this->_args[$method] = $args[0];
			}
		} else {
			throw new Exception(__METHOD__.'调用'.get_class($this).'::'.$method.'不存在');
		}
		return $this;
	}

	Public function getArgs() {
		$args = $this->_args;
		$this->_args = array('field' => '', 'where' => '', 'group' => '', 'order' => '', 'limit' => '', 'alias' => '', 'join' => '');
		return $args;
	}

	Public Static function realTable($table) {
		$str = stristr(trim($table), ' ');
		if ($str) return str_replace($str, '', $table);
		return $table;
	}

	Public function getTable($args) {
		$this->table = self::realTable($this->table);
		if (C('DEBUG')) {
			$fields = $this->getFields();
			if ($fields) J::debug('表<b>'.$this->table.'</b>结构: '.join(',', $fields), 2);
		}
		if (trim($args['alias'])) $this->table .= ' '.$args['alias'];
		return $this->table;
	}

	Public function fetch() {
		$args = $this->getArgs();
		$table = $this->getTable($args);
		$field = $this->parse('field', $args['field']);
		$where = $this->parse('where', $args['where']);
		$group = $this->parse('group', $args['group']);
		$join = $this->parse('join', $args['join']);
		$order = $this->parse('order', $args['order']);
		$sql = 'SELECT '.$field.' FROM '.$table.$join.$where.$group.$order.' LIMIT 1';
		return $this->query($sql, __FUNCTION__);
	}

	Public function fetchAll() {
		$args = $this->getArgs();
		$table = $this->getTable($args);
		$field = $this->parse('field', $args['field']);
		$where = $this->parse('where', $args['where']);
		$group = $this->parse('group', $args['group']);
		$join = $this->parse('join', $args['join']);
		$order = $this->parse('order', $args['order']);
		$limit = $this->parse('limit', $args['limit']);
		$sql = 'SELECT '.$field.' FROM '.$table.$join.$where.$group.$order.$limit;
		return $this->query($sql, __FUNCTION__);
	}

	Public function count($function = 'count') {
		$args = $this->getArgs();
		$table = $this->getTable($args);
		$field = $this->parse('field', $args['field']);
		if (!$field) $field = '*';
		$where = $this->parse('where', $args['where']);
		$join = $this->parse('join', $args['join']);
		$sql = 'SELECT '.strtoupper($function).'('.$field.') FROM '.$table.$join.$where;
		$result = $this->query($sql, __FUNCTION__);
		return is_numeric($result) ? $result : 0;
	}

	Public function filterData($data, $table = '') {
		$result = array();
		if (is_array($data)) {
			$table = trim($table) ? $table : $this->table;
			$fields = $this->getFields(str_replace($this->config['DB_PREFIX'], '', $table));
			foreach ($data as $field => $value) {
				if (in_array(strtolower($field), $fields)) $result[$field] = $value;
			}
		}
		return $result;
	}

	Public function insert($data) {
		$args = $this->getArgs();
		$table = $this->getTable($args);
		$data = $this->filterData($data, $table);
		$fields = $values = array();
		foreach ($data as $field => $value) {
			$fields[] = '`'.$field.'`';
			$values[] = '\''.$this->escapeString($value).'\'';
		}
		$field = $fields ? join(',', $fields) : '';
		$value = $values ? join(',', $values) : '';
		if (!$field) return 0; //如果字段全部为空就直接返回
		$sql = 'INSERT INTO '.$table.' ('.$field.') VALUES ('.$value.')';
		return $this->query($sql, __FUNCTION__);
	}

	Public function update($data) {
		$args = $this->getArgs();
		$table = $this->getTable($args);
		$where = $this->parse('where', $args['where']);
		if (!$where) return 0; //如果不存在修改条件直接返回
		$value = '';
		if (is_array($data)) {
			$data = $this->filterData($data, $table);
			$values = array();
			foreach ($data as $field => $value) {
				$values[] = '`'.$field.'` = \''.$this->escapeString($value).'\'';
			}
			if ($values) $value = join(',', $values);
		} else {
			$value = $data;
		}
		$sql = 'UPDATE '.$table.' SET '.$value.$where;
		return $this->query($sql, __FUNCTION__);
	}

	Public function delete($null = '') {
		$args = $this->getArgs();
		$table = $this->getTable($args);
		$sql = 'DELETE FROM '.$table;
		if (!is_null($null)) {
			$where = $this->parse('where', $args['where']);
			$limit = $this->parse('limit', $args['limit']);
		if (!$where && !$limit) return 0; //如果不存在删除条件直接返回
		$order = $this->parse('order', $args['order']);
		$sql .= $where.$order.$limit;
	}
	return $this->query($sql, __FUNCTION__);
	}

	Abstract Public function escapeString($string);
	Abstract Public function query($sql, $method = '');
	Abstract Public function getFields();
	Abstract Public function beginTransaction();
	Abstract Public function commit();
	Abstract Public function rollBack();
	Abstract Public function lastInsertId();
	Abstract Public function getVersion();

	Public Static function getInstance() {
		throw new Exception(__METHOD__.' [继承类需要定义: getInstance()]');
	}
}